﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using iTextSharp.text;

namespace PocoReport
{
    public class Table : IPart, IContainerPart
    {
        public Style Style { get; protected set; }
        public List<Row> Header { get; protected set; }
        public List<Row> Body { get; protected set; }
        public List<Row> Footer { get; protected set; }
        public string DataSource { get; set; }
        public string Value { get; set; }

        public Table()
        {
            Style = new Style();
            Header = new List<Row>();
            Body = new List<Row>();
            Footer = new List<Row>();
        }

        public void Load(XNode node)
        {
            XElement element = (XElement)node;
            Style = new Style(element);
            DataSource = element.GetAttribValue("DataSource", null);
            Value = element.GetAttribValue("Value", null);
            GetRows(element, "Header", Header);
            GetRows(element, "Body", Body);
            GetRows(element, "Footer", Footer);
        }

        public XNode Save()
        {
            XElement element = new XElement("Table");
            element.SetAttribValue("Style", Style);
            element.SetAttribValue("DataSource", DataSource);
            element.SetAttribValue("Value", Value);
            element.Add(SaveRows(Header, "Header"));
            element.Add(SaveRows(Body, "Body"));
            element.Add(SaveRows(Footer, "Footer"));
            return element;
        }

        private XElement SaveRows(List<Row> section, string name)
        {
            XElement element = new XElement(name);
            foreach (Row row in section)
            {
                element.Add(row.Save());
            }
            return element;
        }

        private void GetRows(XElement element, string name, List<Row> section)
        {
            XElement header = element.Element(name);
            if (header != null)
            {
                foreach (XElement rowElement in header.Elements("Row"))
                {
                    Row row = new Row();
                    row.Load(rowElement);
                    section.Add(row);
                }
            }
        }

        public virtual IElement GetPdfElement(Document document, Style parentStyle, Scope scope)
        {
            int columnCount = GetColumnCount();
            Style.Properties["columns"] = columnCount.ToString();
            Style mergedStyle = Style.Merge(parentStyle, Style);
            iTextSharp.text.Table table = iTextSharp.text.factories.ElementFactory.GetTable(mergedStyle.Properties);

            AddPdfRows(mergedStyle, document, scope, table, Header);
            
            if (DataSource != null && Value != null)
            {
                IEnumerable dataSourceValue = (IEnumerable)scope.GetValue(DataSource);
                if (dataSourceValue != null)
                {
                    Scope innerScope = new Scope(scope);
                    foreach (object value in dataSourceValue)
                    {
                        innerScope.Set(Value, value);
                        AddPdfRows(mergedStyle, document, innerScope, table, Body);
                    }
                }
            }
            else
            {
                AddPdfRows(mergedStyle, document, scope, table, Body);
            }
            
            AddPdfRows(mergedStyle, document, scope, table, Footer);
            return table;
        }

        public int GetColumnCount()
        {
            int columnCount = Header.Max(r => r.Cells.Count);
            columnCount = Math.Max(columnCount, Body.Max(r => r.Cells.Count));
            columnCount = Math.Max(columnCount, Footer.Max(r => r.Cells.Count));
            return columnCount;
        }

        private void AddPdfRows(Style mergedStyle, Document document, Scope scope, iTextSharp.text.Table table, List<Row> section)
        {
            foreach (Row row in section)
            {
                IElement cells = row.GetPdfElement(document, mergedStyle, scope);
                foreach (iTextSharp.text.Cell cell in cells.Chunks)
                {
                    table.AddCell(cell);
                }
            }
        }

        IList<IPart> IContainerPart.Parts
        {
            get 
            {
                List<IPart> parts = new List<IPart>();
                parts.AddRange(Header.Cast<IPart>());
                parts.AddRange(Body.Cast<IPart>());
                parts.AddRange(Footer.Cast<IPart>());
                return parts; 
            }
        }
    }
}
